import { reactive, ref, watch, type Ref, shallowReactive, onUnmounted } from "vue"
import { createHighlighter, bundledThemesInfo, bundledLanguagesInfo } from "shiki";

import type { BundledLanguageInfo, BundledThemeInfo, HighlighterGeneric } from "@shikijs/types"
import type { IShiki } from "./inter";



export default (outputRef: Ref<HTMLElement>, props: IShiki.Props) => {
    // const {lang = 'json',theme = 'min-light'} = props;
    const lang = ref<string>(props.lang || 'json');
    const theme = ref<string>(props.theme || 'min-light');
    const isLoading = ref(false)
    //
    const input = ref(props.modelValue || '')
    const output = ref('')
    const preStyle = ref('')
    //
    const decorations = props.decorations || []
    const transformers = props.transformers || []

    //
    const inputHooks = shallowReactive<((v: string) => void)[]>([])
    const outputHooks = shallowReactive<((v: string) => void)[]>([])
    if (props.inputHook) {
        inputHooks.push(props.inputHook)
    }
    if (props.outputHook) {
        outputHooks.push(props.outputHook)
    }
    //
    const init = async () => {
        const highlighter = await createHighlighter({ themes: [theme.value], langs: [lang.value] });
        render(highlighter);
        //
        watch([lang, theme], async ([l, t]: any) => {
            isLoading.value = true;
            await Promise.all([highlighter.loadLanguage(l), highlighter.loadTheme(t)])
            render(highlighter);
        })
        //
        watch(input, (v) => {
            render(highlighter)
            for (const f of inputHooks) {
                f(v)
            }
        })

        // onUnmounted(() => {
        //     highlighter.dispose();
        // })

        return () => render(highlighter);
    }

    const render = async (highlighter: HighlighterGeneric<any, any>) => {
        if(props.tempValue){
            
        }
        output.value = highlighter.codeToHtml(input.value, {
            lang: lang.value || 'json',
            theme: theme.value || 'min-light',
            decorations,
            transformers: [
                {
                    preprocess(code,options) {
                        console.log('code === ',code)
                        if (code.endsWith('\n')) return `${code}\n`
                    },
                    // tokens(...args){
                    //     console.log('tokens === ',args)
                    // },
                    // span(...args){
                    //     console.log('span === ',args)
                    // },
                    pre(node) {
                        preStyle.value = node.properties?.style as string || ''
                    }
                },
                ...transformers
            ]
        })
        isLoading.value = false;
        for (const f of outputHooks) {
            f(output.value)
        }
    }

    init();
    //
    const langChange = (item: BundledLanguageInfo) => {
        console.log('lang item ==> ', item)
        lang.value = item.id;
    }
    const themeChange = (item: BundledThemeInfo) => {
        console.log('theme item ==> ', item)
        theme.value = item.id;
    }

    const onInput = (e: any) => {
        input.value = e.target.value;
    }
    const onScroll = (e: any) => {
        const b = outputRef.value;
        if (!b) return;
        const t = e.target;
        b.scrollTop = t.scrollTop;
        b.scrollLeft = t.scrollLeft;
    }

    const keys = new Set<string>();
    const onKeydown = (e: KeyboardEvent) => {
        keys.add(e.key)
        if (props.enterModify) {
            if (e.key == 'Enter' && keys.has(props.enterModify) && !e.isComposing) {
                // enter
                e.stopPropagation();
                e.preventDefault();
                // 换行
                const el: any = e.target;
                const val = el.value;
                const si = el.selectionStart;
                const ei = el.selectionEnd || val.length;
                el.value = val.slice(0, si) + '\n' + val.slice(ei)
                return;
            }
        }
        if (props.keydown) {
            props.keydown(e, keys)
        }
    }
    const onKeyup = (e: KeyboardEvent) => {
        keys.delete(e.key)
    }



    // const addHooks = (f:(v:string) => void,name:"input"|"output"='input') => {
    //     switch(name){
    //         case "input":
    //             inputHooks.push(f)    
    //         break;
    //         case "output":
    //             outputHooks.push(f)    
    //         break;
    //     }
    // }

    //
    return {
        lang,
        theme,
        input,
        output,
        preStyle,
        bundledThemesInfo,
        bundledLanguagesInfo,
        langChange,
        themeChange,
        //
        onInput,
        onScroll,
        onKeydown,
        onKeyup,
        // refresh
        // addHooks,
    }
}